﻿using System;
using System.Globalization;
using System.IO;
using System.Reflection;

namespace Cpuss.ReportGenerator
{

    /// <summary>
    /// Factory used for creating instances of runtime loaded <see cref="Cpuss.IStrategy"/> plugins.
    /// </summary>
    public class StrategyFactory
    {

        private readonly string _strategy;
        private readonly object[] _args;

        /// <summary>
        /// Initializes a new <see cref="StrategyFactory"/>.
        /// </summary>
        /// <param name="strategy">Strategy to create an instance of.</param>
        /// <exception cref="ArgumentNullException"><strong>strategy</strong> is <strong>null</strong>.</exception>
        private StrategyFactory(string strategy)
        {
            if (strategy == null)
            {
                throw new ArgumentNullException("strategy");
            }

            _strategy = strategy;
        }

        /// <summary>
        /// Initializes a new <see cref="StrategyFactory"/>.
        /// </summary>
        /// <param name="strategy">Strategy to create an instance of.</param>
        /// <param name="args">Arguments for strategy constructor.</param>
        /// <exception cref="ArgumentNullException"><strong>args</strong> is <strong>null</strong>.</exception>
        public StrategyFactory(string strategy, object[] args)
            : this(strategy)
        {
            if (args == null)
            {
                throw new ArgumentNullException("args");
            }

            _args = args;
        }

        /// <summary>
        /// Creates an instance of an <see cref="IStrategy"/>.
        /// </summary>
        /// <returns><see cref="IStrategy"/> instance if the strategy was found in one of the plugin assemblies; otherwise null.</returns>
        /// <exception cref="DirectoryNotFoundException"><strong>Plguins</strong> directory does <strong>not</strong> exist.</exception>
        public IStrategy CreateInstance()
        {
            string[] plugins = Directory.GetFiles(string.Format(CultureInfo.InvariantCulture, "{0}\\Plugins", Directory.GetCurrentDirectory()), "*.dll");
            foreach (string plugin in plugins)
            {
                Assembly assembly = Assembly.LoadFrom(plugin);
                foreach (Type type in assembly.GetTypes())
                {
                    if (type.GetInterface("Cpuss.IStrategy") != null && _strategy == type.Name && _args.Length < 1)
                    {
                        return Activator.CreateInstance(type) as IStrategy;
                    }
                    else if (type.GetInterface("Cpuss.IStrategy") != null && _strategy == type.Name && _args.Length > 0)
                    {
                        return Activator.CreateInstance(type, _args) as IStrategy;
                    }
                }
            }
            return null;
        }

    }

}
